package repositories

import (
	"context"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/request"
	"go.didapinche.com/time"
	"gorm.io/gorm"
	"strconv"
)

type AlertCurrentRepository interface {
	Create(ctx context.Context, alert *models.AlertCurrent) error
	Delete(ctx context.Context, graphID uint64) error
	FindAll(ctx context.Context) ([]*models.AlertCurrent, error)
	Find(ctx context.Context, req *request.AlertHistoryReq) ([]*models.AlertCurrent, error)
	UpdateByID(ctx context.Context, ids []uint64, user string) error
	FindByGroupID(ctx context.Context, grouIDs []string) ([]*models.AlertCurrent, error)
	FindByGroupAndLevel(ctx context.Context, grouIDs []string, level int, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByAppID(ctx context.Context, appID int, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByApiID(ctx context.Context, apiID int, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByDashboardID(ctx context.Context, dashboardID int, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByDate(ctx context.Context, end time.Time) ([]*models.AlertCurrent, error)
	FindByGraphID(ctx context.Context, graphID uint64, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByID(ctx context.Context, ID uint64) (*models.AlertCurrent, error)
	FirstByGraphID(ctx context.Context, graphID uint64) (*models.AlertCurrent, error)
}

type alertCurrentRepository struct {
	db *gorm.DB
}

func NewAlertCurrentRepository(db *gorm.DB) AlertCurrentRepository {
	return &alertCurrentRepository{
		db: db,
	}
}

func (a alertCurrentRepository) FindAll(ctx context.Context) (result []*models.AlertCurrent, err error) {
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&result).Error; err != nil {
		return nil, errors.Wrap(err, "find all apiInfo error")
	}
	return result, nil
}

func (a alertCurrentRepository) Create(ctx context.Context, alert *models.AlertCurrent) error {
	return a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Create(alert).Error
}

func (a alertCurrentRepository) Delete(ctx context.Context, graphID uint64) error {
	return a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Where("graph_id=?", graphID).Delete(&models.AlertCurrent{}).Error
}

func (a alertCurrentRepository) FindByGroupID(ctx context.Context, grouIDs []string) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "dev_group_id=?", grouIDs).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGroupID error")
	}
	return alerts, nil
}
func (a alertCurrentRepository) FindByID(ctx context.Context, id uint64) (*models.AlertCurrent, error) {
	alert := new(models.AlertCurrent)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).First(&alert, "id=?", id).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByID error")
	}
	return alert, nil
}

func (a alertCurrentRepository) FindByGroupAndLevel(ctx context.Context, grouIDs []string, level int, start, end time.Time) ([]*models.AlertCurrent, error) {
	query := ""
	if level > 0 {
		query += " and level =" + strconv.Itoa(level)
	}
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "dev_group_id in ? and (start_alert_time between ? and ?)"+query, grouIDs, start, end).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGroupID error")
	}
	return alerts, nil
}
func (a alertCurrentRepository) FindByAppID(ctx context.Context, appID int, start, end time.Time) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "app_id=?  and (start_alert_time between ? and ?)", appID, start, end).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGroupID error")
	}
	return alerts, nil
}

func (a alertCurrentRepository) FindByApiID(ctx context.Context, apiID int, start, end time.Time) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "api_id=?  and (start_alert_time between ? and ?)", apiID, start, end).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGroupID error")
	}
	return alerts, nil
}
func (a alertCurrentRepository) FindByDashboardID(ctx context.Context, dashboardID int, start, end time.Time) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "dashboard_id=?  and (start_alert_time between ? and ?)", dashboardID, start, end).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGroupID error")
	}
	return alerts, nil
}

//L0级别报警
func (a alertCurrentRepository) FindByDate(ctx context.Context, end time.Time) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "start_alert_time<? and alert_level!=2", end).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByDate error")
	}
	return alerts, nil
}

func (a alertCurrentRepository) FindByGraphID(ctx context.Context, graphID uint64, start, end time.Time) ([]*models.AlertCurrent, error) {
	alerts := make([]*models.AlertCurrent, 0)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Find(&alerts, "graph_id=?  and (start_alert_time between ? and ?)", graphID, start.String(), end.String()).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FindByGraphID error")
	}
	return alerts, nil
}

func (a alertCurrentRepository) FirstByGraphID(ctx context.Context, graphID uint64) (*models.AlertCurrent, error) {
	alert := new(models.AlertCurrent)
	if err := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).First(&alert, "graph_id=?", graphID).Error; err != nil {
		return nil, errors.Wrap(err, "call alertCurrentRepository FirstByGraphID error")
	}
	return alert, nil
}

func (a alertCurrentRepository) Find(ctx context.Context, req *request.AlertHistoryReq) ([]*models.AlertCurrent, error) {
	db := a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Where("start_alert_time between ? and ?", req.StartTime, req.EndTime).Order("start_alert_time desc ")
	alerts := make([]*models.AlertCurrent, 0)
	if req.AlertLevel != -1 {
		db = db.Where("alert_level=?", req.AlertLevel)
	}
	if req.ClaimStatus != -1 {
		db = db.Where("claim_status=?", req.ClaimStatus)
	}
	if req.AppID != 0 {
		if err := db.Where("app_id=?", req.AppID).Scan(&alerts).Error; err != nil {
			return nil, err
		}
		return alerts, nil
	} else if req.ApiID != 0 {
		if err := db.Where("api_id=? ", req.ApiID).Scan(&alerts).Error; err != nil {
			return nil, err
		}
		return alerts, nil
	} else if req.HostID != 0 {
		if err := db.Where("host_id=?", req.HostID).Scan(&alerts).Error; err != nil {
			return nil, err
		}
		return alerts, nil
	} else if req.DashboardID != 0 {
		if err := db.Where("dashboard_id in ?", req.DashboardIDs).Scan(&alerts).Error; err != nil {
			return nil, err
		}
		return alerts, nil
	} else if req.GraphID != 0 {
		if err := db.Where("graph_id=?", req.GraphID).Scan(&alerts).Error; err != nil {
			return nil, err
		}
		return alerts, nil
	} else {
		if req.Query == "" {
			if err := db.Scan(&alerts).Error; err != nil {
				return nil, err
			}
			return alerts, nil
		} else {
			db2 := a.db
			if len(req.AppIDs) > 0 {
				db2 = db2.Or("app_id in ?", req.AppIDs)
			}
			if len(req.ApiIDs) > 0 {
				db2 = db2.Or("api_id in ?", req.ApiIDs)
			}
			if len(req.DashboardIDs) > 0 {
				db2 = db2.Or("dashboard_id in ?", req.DashboardIDs)
			}
			if len(req.HostIDs) > 0 {
				db2 = db2.Or("host_id in ?", req.HostIDs)
			}
			if err := db.Where(db2).Scan(&alerts).Error; err != nil {
				return nil, err
			}
			return alerts, nil
		}
	}
}

func (a alertCurrentRepository) UpdateByID(ctx context.Context, ids []uint64, user string) error {
	return a.db.WithContext(ctx).Table(models.AlertCurrentTableName).Where("id in ?", ids).Updates(&models.AlertCurrent{ClaimStatus: 1, ClaimUser: user}).Error

}
